package generator

import (
	"boy-go/generator/model"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"os"
	"strings"
	"text/template"
	"unicode"
)

func ReadMysql(tableName string) []model.Field {
	dsn := "admin:admin@tcp(127.0.0.1:3306)/boy-go?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("failed to connect database: ", err)
	}
	query := `
		SELECT
		  COLUMN_NAME AS fieldName,
		  COLUMN_KEY as isKey,
		  DATA_TYPE as dataType,
		  IS_NULLABLE as isNull,
		  COLUMN_COMMENT AS comment
		FROM
		  information_schema.COLUMNS
		WHERE
		  TABLE_SCHEMA = DATABASE()
		  AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION asc
		`
	// 使用 GORM 执行原生 SQL
	var columns []model.ColumnInfo
	result := db.Raw(query, tableName).Scan(&columns)
	if result.Error != nil {
		log.Fatal(result.Error)
	}
	fields := make([]model.Field, 0)
	for _, col := range columns {
		fmt.Printf("字段名: %-20s 注释: %s key:%s dataType:%s \n ", col.FieldName, col.Comment, col.IsKey, col.FieldType)
		fieldName := toUpperFirst(ToCamelCase(col.FieldName))
		voFieldName := fieldName
		fieldType := dateType2FieldType(col.FieldType)
		voFieldType := fieldType
		if col.FieldType == "datetime" || col.FieldType == "date" {
			voFieldType = "string"
			colName := col.FieldName
			colNames := strings.Split(colName, "_")
			if len(colNames) > 1 {
				lastName := colNames[len(colNames)-1]
				if lastName == "time" {
					colNames[len(colNames)-1] = "at"
					colName = ""
					for i := 0; i < len(colNames); i++ {
						colName += colNames[i] + "_"
					}
					fieldName = toUpperFirst(ToCamelCase(colName))
				}
			}
		}
		isPk := "0"
		if col.IsKey == "PRI" {
			isPk = "1"
		}
		field := model.Field{
			ColumnId:      1,             // 编号
			TableId:       1,             // 归属表编号
			ColumnComment: col.Comment,   // 列描述
			ColumnName:    col.FieldName, // 列名称
			ColumnType:    col.FieldType, // 列类型
			DictType:      "",            // 字典类型
			HtmlType:      "",            // 显示类型（文本框、文本域、下拉框、复选框、单选框、日期控件）
			IsEdit:        "1",           // 是否编辑字段（1是）
			IsIncrement:   "0",           // 是否自增（1是）
			IsInsert:      "1",           // 是否为插入字段（1是）
			IsList:        "0",           // 是否列表字段（1是）
			IsPk:          isPk,          // 是否主键（1是）
			IsQuery:       "1",           // 是否查询字段（1是）
			IsRequired:    "1",           // 是否必填（1是）
			QueryType:     "EQ",          // 查询方式（等于、不等于、大于、小于、范围）
			Sort:          1,             // 排序
			FieldName:     fieldName,     // Model字段名
			FieldType:     fieldType,     // Model类型
			VoFieldName:   voFieldName,   // Vo字段名
			VoFieldType:   voFieldType,   // Vo类型
		}
		fields = append(fields, field)
	}
	return fields
}

// 数据库的类型转换为GO 字段类型
func dateType2FieldType(dataType string) string {
	switch dataType {
	case "int":
		return "int64"
	case "float":
		return "float64"
	case "double":
		return "float64"
	case "date":
		return "time.Time"
	case "bigint":
		return "int64"
	case "tinyint":
		return "int"
	case "decimal":
		return "float64"
	case "datetime":
		return "time.Time"
	default:
		return "string"
	}
}

// 将 snake_case 转换为 CamelCase
func ToCamelCase(s string) string {
	parts := strings.Split(s, "_")
	for i, part := range parts {
		if i == 0 {
			parts[i] = strings.ToLower(part)
		} else {
			parts[i] = strings.Title(part)
		}
	}
	return strings.Join(parts, "")
}

// 将第一个字符转为大写
func toUpperFirst(s string) string {
	if len(s) < 1 {
		return ""
	}
	r := []rune(s)
	r[0] = unicode.ToUpper(r[0])
	return string(r)
}

// 将第一个字符转为小写
func toLowerFirst(s string) string {
	if len(s) < 1 {
		return ""
	}
	r := []rune(s)
	r[0] = unicode.ToLower(r[0])
	return string(r)
}

func createTempl(mode string, name string) *template.Template {
	tmplByte, err := os.ReadFile("./templates/" + mode + "/" + name + ".go.tmpl")
	if err != nil {
		fmt.Println("read tmpl failed, err:", err)
		return nil
	}
	funcMap := template.FuncMap{
		"lowerFirst": toLowerFirst,
	}
	tmpl := template.Must(template.New("model").Funcs(funcMap).Parse(string(tmplByte)))
	return tmpl
}
func createOutFile(name string, fileName string) *os.File {
	outputDir := "./output/"
	outputDirs := []string{
		outputDir + "model",
		outputDir + "vo",
		outputDir + "repository",
		outputDir + "service",
		outputDir + "handler",
	}
	// 判断outputDirs文件夹是否存在
	for _, dir := range outputDirs {
		if _, err := os.Stat(dir); os.IsNotExist(err) {
			err := os.MkdirAll(dir, os.ModePerm)
			if err != nil {
				panic(fmt.Errorf("创建文件夹 %s 失败: %w", dir, err))
			}
		}
	}
	ext := ""
	if name != "model" {
		ext = "_" + name
	}
	if name == "serviceimpl" {
		name = "service"
		ext = "_serviceimpl"
	}
	mfile, err := os.Create(outputDir + name + "/" + strings.ToLower(fileName) + ext + ".go")
	if err != nil {
		panic(fmt.Errorf("创建 "+name+" 文件失败: %w", err))
	}
	return mfile
}

// 渲染模版
func renderTemplate(tmpl *template.Template, name string, data model.TemplateData) {
	fileName := data.ClassName
	outFile := createOutFile(name, fileName)
	// 执行模板渲染
	if err := tmpl.Execute(outFile, data); err != nil {
		panic(fmt.Errorf("渲染 "+name+" 模板失败: %w", err))
	}
}
func Generator(data model.TemplateData) {
	// 获取并打印当前工作目录
	wd, _ := os.Getwd()
	fmt.Println("当前工作目录:", wd)

	// 加载模板文件
	modelTmpl := createTempl("go", "model")
	voTmpl := createTempl("go", "vo")
	repositoryTmpl := createTempl("go", "repository")
	serviceTmpl := createTempl("go", "service")
	serviceimplTmpl := createTempl("go", "serviceimpl")
	handlerTmpl := createTempl("go", "handler")

	renderTemplate(modelTmpl, "model", data)
	renderTemplate(voTmpl, "vo", data)
	renderTemplate(repositoryTmpl, "repository", data)
	renderTemplate(serviceTmpl, "service", data)
	renderTemplate(serviceimplTmpl, "serviceimpl", data)
	renderTemplate(handlerTmpl, "handler", data)
	fmt.Println("✅ 代码生成成功！")
}
